﻿package {
	
import caurina.transitions.*;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.filters.BlurFilter;
import flash.geom.Point;
import flash.geom.Rectangle;



public class Screen extends Sprite {
	
	// Properties
	// -----------------------------------------------------------
	
	private const PIXEL_MIN:Number = 15;
	
	public var screenWidth:Number;
	public var screenHeight:Number;
	
	private var display:Bitmap;
	private var temp:BitmapData;
	private var pixels:Array;
	
	private var pixelSize:Number;
	private var gateSize:Number;
	private var sourceObject:*;
	private var sourceOrigin:Point;
	private var sourceBMD:BitmapData;
	private var pixelsOn:Boolean;
	
	
	
	// Constructor
	// -----------------------------------------------------------
	
	public function Screen($width:Number = NaN,
				  $height:Number = NaN,
				  $pixelSize:Number = NaN,
				  $gateSize:Number = NaN) {
		
		display	= new Bitmap();
		
		if ($width) setSize($width, $height, $pixelSize, $gateSize);
		
		pixelsOn	= false;
	}
	
	
	
	// Public Functions
	// -----------------------------------------------------------
	
	public function draw($source:*,
				$origin:Point = null,
				$blur:int = 0,
				$duration:Number = 0):void {
		
		sourceOrigin	= ($origin == null) ? new Point() : $origin;
		
		if ($source is BitmapData) {
			sourceBMD = $source;
		}
		else {
			sourceObject = $source;
			sourceBMD = new BitmapData($source.width, $source.height, true, 0x00000000);
			sourceBMD.draw(sourceObject);
		}
		
		render($blur, $duration);
	}
	
	
	public function setSize($width:Number,
				   $height:Number,
				   $pixelSize = PIXEL_MIN,
				   $gateSize = 0):void {
		
		// Empty Previous Pixels
		while (numChildren > 0) removeChildAt(0);
		
		// set Pixel Dimensions
		pixelSize	= ($pixelSize > PIXEL_MIN) ? $pixelSize : PIXEL_MIN;
		gateSize	= $gateSize;
		
		// Set Screen Dimensions
		var w:Number		= ($width < 2880) ? $width : 2880;
		var h:Number		= ($height < 2880) ? $height : 2880;
		
		display.bitmapData 	= new BitmapData(w, h, true, 0x00000000);
		temp			= new BitmapData(w, h, true, 0x00000000);
		pixels			= new Array();
		
		screenWidth		= w / pixelSize;
		screenHeight		= h / pixelSize;
		
		build();
	}
	
	
	public function showPixels():void {
		
		for (var col in pixels) {
			for (var row in pixels[col]) {
				
				pixels[col][row].visible = true;
			}
			
		}
		pixelsOn = true;
	}
	
	
	public function hidePixels():void {
		
		for (var col in pixels) {
			for (var row in pixels[col]) {
				
				pixels[col][row].visible = false;
			}
			
		}
		pixelsOn = false;
	}
	
	
	public function togglePixels():void {
		
		if (pixelsOn) {
			hidePixels();
		}
		else {
			showPixels();
		}
	}
	
	
	
	// Private Functions
	// -----------------------------------------------------------
	
	private function build():void {
		
		// General Settings
		alpha		= 0;
		addChild	(display);
		
		// Build Pixels
		var col:int = 0;
		var row:int = 0;
		var origin:Point = new Point();
		
		var pixel:Pixel;
		
		for (col = 0; col < screenWidth; col++) {
			
			origin.y = 0;
			
			pixels[col] = new Array();
			
			for (row = 0; row < screenHeight; row++) {
				
				pixel 		= new Pixel(temp, pixelSize, gateSize);
				pixel.origin 	= origin;
					
				pixels[col][row] = pixel;
				addChild(pixel);
				
				origin.offset(0, pixelSize);
			}
			
			origin.offset(pixelSize, 0);
		}
		
		if (pixelsOn) showPixels();
	}
	
	
	private function render($blur:int = 0, $duration:Number = 0):void {
		
		this.alpha = 0;
		
		// Change Pixels' color
		temp.lock();
		
		for (var col in pixels) {
			
			for (var row in pixels[col]) {
				
				var getX:int			= sourceOrigin.x + col;
				var getY:int 			= sourceOrigin.y + row;
				
				var color:uint 		= sourceBMD.getPixel32(getX, getY);
				pixels[col][row].color	= color;
			}
			
		}
		
		temp.unlock();
		
		// Remove source object from display
		if (sourceObject != undefined && sourceObject.parent) {
			sourceObject.parent.removeChild(sourceObject);
		}
		
		// Apply Blur Fitler
		if ($blur > 0) {
			display.bitmapData.applyFilter(temp,
							   new Rectangle(0, 0, display.width, display.height),
							   new Point(),
							   new BlurFilter($blur, $blur));
		}
		else {
			display.bitmapData = temp;
		}
		
		// Animate
		Tweener.addTween(this, {alpha:1, time:$duration, transition:"linear", skipUpdates:1});
			
	}
	
	
}
}